package com.rex.saas.controller;

import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.rex.saas.bean.*;
import com.rex.saas.bean.request.GatewayAddRequest;
import com.rex.saas.bean.request.GatewayAddSubDeviceRequest;
import com.rex.saas.bean.request.GatewayBindSubDeviceRequest;
import com.rex.saas.bean.request.GatewayUnBindSubDeviceRequest;
import com.rex.saas.constants.Constants;
import com.rex.saas.db.entity.PaasGatewayCredentials;
import com.rex.saas.db.entity.SaasDeviceInfo;
import com.rex.saas.db.entity.SaasSpaceInfo;
import com.rex.saas.service.DeviceService;
import com.rex.saas.service.GatewayService;
import com.rex.saas.service.RexolarApiClient;
import com.rex.saas.service.SpaceService;
import com.rex.saas.utils.JwtUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@RestController
@Slf4j
@RequestMapping("/gateway")
public class GatewayController {

    @Autowired
    private GatewayService gatewayService;

    @Autowired
    private DeviceService deviceService;

    @Autowired
    private SpaceService spaceService;

    @Autowired
    private RexolarApiClient rexolarApiClient;
    @GetMapping("/devices")
    public BaseResponse devices(HttpServletRequest request, @RequestParam Long id, @RequestParam Long spaceId) {
        String token = request.getHeader("token");
        Boolean flag =  checkGateway(id, token);
        if(!flag){
            log.error("devices checkGateway error, id:{}, token:{}", id, token);
            return BaseResponse.error("非法网关", ResultCode.PARAM_ERROR);
        }
        PaasGatewayCredentials gateway = gatewayService.getById(id);
        return BaseResponse.ok(gatewayService.getPaasGwDevices(gateway.getGwId(), spaceId, gateway.getTenantId()));
    }

    private Boolean checkGateway(Long id, String token) {
        PaasGatewayCredentials gatewayCredentials = gatewayService.getById(id);
        if (gatewayCredentials == null){
            log.error("checkGateway , gateway is not exist, id:{}", id);
            return false;
        }
        if (!gatewayCredentials.getTenantId().equals(JwtUtils.getTenantId( token))){
            log.error("checkGateway , gateway tenantId not match, tenantId:{}, gateway:{}", JwtUtils.getTenantId( token), gatewayCredentials);
            return false;
        }
        DeviceBasicData device = rexolarApiClient.getDeviceByDeviceName(gatewayCredentials.getGwName(), token);
        if(device==null){
            log.error("checkGateway DeviceBasicData is null, deviceName:{}", gatewayCredentials.getGwName());
            return false;
        }
        if(!device.getTenantId().equals(JwtUtils.getTenantId(token))){
            log.error("DeviceBasicData device tenantId not match, tenantId:{}, device:{}", JwtUtils.getTenantId(token), device);
            return false;
        }
        return true;
    }


    @GetMapping("/detail")
    public BaseResponse detail(HttpServletRequest request, @RequestParam Long id) {
        String token = request.getHeader("token");
        Boolean flag =  checkGateway(id, token);
        if(!flag){
            log.error("detail checkGateway error, id:{}, token:{}", id, token);
            return BaseResponse.error("非法网关", ResultCode.PARAM_ERROR);
        }

        PaasGatewayCredentials gatewayCredentials = gatewayService.getById(id);
        GatewayInfoDetail gatewayInfoDetail = new GatewayInfoDetail();
        BeanUtils.copyProperties(gatewayCredentials, gatewayInfoDetail);
        Map<String, Object> attributes = deviceService.getAttributes(gatewayCredentials.getGwId(), token,
                new String[] {Constants.LAST_CONNECT_TIME, Constants.LAST_DISCONNECT_TIME, Constants.ACTIVE});
        if(!CollectionUtils.isEmpty( attributes)){
            Long lastConnectTime = (Long) attributes.get(Constants.LAST_CONNECT_TIME);
            Long lastDisconnectTime = (Long) attributes.get(Constants.LAST_DISCONNECT_TIME);
            Boolean active = (Boolean) attributes.get(Constants.ACTIVE);
            gatewayInfoDetail.setLastConnectTime(lastConnectTime);
            gatewayInfoDetail.setLastDisconnectTime(lastDisconnectTime);
            gatewayInfoDetail.setStatus(active?1:0);
        }
        DeviceProfileBasicData profile = rexolarApiClient.getDeviceProfileById(token, gatewayCredentials.getProfileId());
        if (profile!=null){
            gatewayInfoDetail.setProductKey(profile.getName());
            gatewayInfoDetail.setDescription(profile.getDescription());
            gatewayInfoDetail.setTransportType(profile.getTransportType());
            gatewayInfoDetail.setImage(profile.getImage());
        }

        return BaseResponse.ok(gatewayInfoDetail);
    }

    @GetMapping("/list")
    public BaseResponse list(HttpServletRequest request, @RequestParam Long spaceId) {
        String token = request.getHeader("token");
        SaasSpaceInfo space = spaceService.getSpaceById(spaceId);
        if(space==null){
            log.error("list space is null, spaceId:{}", spaceId);
            return BaseResponse.error("空间不存在",ResultCode.PARAM_ERROR);
        }
        if(!space.getTenantId().equals(JwtUtils.getTenantId(token))){
            log.error("list space tenantId not match, tenantId:{}, saasSpaceInfo:{}", JwtUtils.getTenantId(token), space);
            return BaseResponse.error("非法空间",ResultCode.PARAM_ERROR);
        }

        return BaseResponse.ok(gatewayService.list(spaceId));
    }

    @PostMapping("/add")
    @ResponseBody
    public BaseResponse add(HttpServletRequest request, @RequestBody GatewayAddRequest gatewayAddRequest) {
        log.info("add, addGatewayRequest:{}", gatewayAddRequest);
        String token = request.getHeader("token");
        List<String> roles = JwtUtils.getRole(token);
        if (!roles.contains(Constants.TENANT_ADMIN)) {
            log.error("add no permission,addGatewayRequest:{}", gatewayAddRequest);
            return BaseResponse.error("没有权限", ResultCode.PARAM_ERROR);
        }
        if (StringUtils.isBlank(gatewayAddRequest.getGwName())){
            log.error("addGatewayRequest gwName is null, addGatewayRequest:{}", gatewayAddRequest);
            return BaseResponse.error("deviceName参数为空", ResultCode.PARAM_ERROR);
        }
        if (StringUtils.isBlank(gatewayAddRequest.getClientId())){
            log.error("addGatewayRequest clientId is null, addGatewayRequest:{}", gatewayAddRequest);
            return BaseResponse.error("clientId参数为空", ResultCode.PARAM_ERROR);
        }
        if (StringUtils.isBlank(gatewayAddRequest.getUsername())){
            log.error("addGatewayRequest username is null, addGatewayRequest:{}", gatewayAddRequest);
            return BaseResponse.error("username参数为空", ResultCode.PARAM_ERROR);
        }
        if (StringUtils.isBlank(gatewayAddRequest.getPassword())){
            log.error("addGatewayRequest password is null, addGatewayRequest:{}", gatewayAddRequest);
            return BaseResponse.error("password参数为空", ResultCode.PARAM_ERROR);
        }
        if (gatewayAddRequest.getSpaceId()==null){
            log.error("addGatewayRequest spaceId is null, addGatewayRequest:{}", gatewayAddRequest);
            return BaseResponse.error("spaceId参数为空", ResultCode.PARAM_ERROR);
        }

        List<PaasGatewayCredentials> gws = gatewayService.getGwByName(gatewayAddRequest.getGwName());
        if (!CollectionUtils.isEmpty(gws)){
            log.error("addGatewayRequest gwName is exist, addGatewayRequest:{}", gatewayAddRequest);
            return BaseResponse.error("网关名称重复:"+gatewayAddRequest.getGwName(), ResultCode.PARAM_ERROR);
        }

        List<SaasDeviceInfo> device = deviceService.getByDeviceName(gatewayAddRequest.getGwName());
        if (!CollectionUtils.isEmpty(device)){
            log.error("addGatewayRequest deviceName is exist, addGatewayRequest:{}", gatewayAddRequest);
            return BaseResponse.error("设备名称重复:"+gatewayAddRequest.getGwName(), ResultCode.PARAM_ERROR);
        }
        gws = gatewayService.getGwByClientId(gatewayAddRequest.getClientId());
        if (!CollectionUtils.isEmpty(gws)){
            log.error("addGatewayRequest clientId is exist, addGatewayRequest:{}", gatewayAddRequest);
            return BaseResponse.error("网关clientId重复:"+gatewayAddRequest.getClientId(), ResultCode.PARAM_ERROR);
        }

        SaasSpaceInfo space = spaceService.getSpaceById(gatewayAddRequest.getSpaceId());
        if(space==null){
            log.error("addGatewayRequest space is null, addGatewayRequest:{}", gatewayAddRequest);
            return BaseResponse.error("空间不存在",ResultCode.PARAM_ERROR);
        }
        return BaseResponse.ok(gatewayService.add(gatewayAddRequest,  token));
    }

    @PostMapping("/bindSubDevice")
    @ResponseBody
    public BaseResponse bindSubDevice(HttpServletRequest request, @RequestBody GatewayBindSubDeviceRequest gatewayBindSubDeviceRequest) {
        log.info("bindSubDevice, gatewayBindSubDeviceRequest:{}", gatewayBindSubDeviceRequest);
        if (StringUtils.isBlank(gatewayBindSubDeviceRequest.getDeviceName())){
            log.error("bindSubDevice deviceName is null, gatewayBindSubDeviceRequest:{}", gatewayBindSubDeviceRequest);
            return BaseResponse.error("参数为空", ResultCode.PARAM_ERROR);
        }
        if (gatewayBindSubDeviceRequest.getGwId()==null){
            log.error("bindSubDevice gwId is null, gatewayBindSubDeviceRequest:{}", gatewayBindSubDeviceRequest);
            return BaseResponse.error("参数为空", ResultCode.PARAM_ERROR);
        }
        String token = request.getHeader("token");
        Boolean flag =  checkGateway(gatewayBindSubDeviceRequest.getGwId(), token);
        if(!flag){
            log.error("bindSubDevice checkGateway error, id:{}, token:{}", gatewayBindSubDeviceRequest.getGwId(), token);
            return BaseResponse.error("非法网关", ResultCode.PARAM_ERROR);
        }
        DeviceBasicData device = rexolarApiClient.getDeviceByDeviceName(gatewayBindSubDeviceRequest.getDeviceName(), token);
        if(device==null){
            log.error("bindSubDevice getDeviceByDeviceName error, deviceName:{}", gatewayBindSubDeviceRequest.getDeviceName());
            return BaseResponse.error("设备不存在", ResultCode.PARAM_ERROR);
        }
        if (!device.getTenantId().equals(JwtUtils.getTenantId(token))){
            log.error("bindSubDevice tenantId not match, tenantId:{}, device:{}", JwtUtils.getTenantId(token), device);
            return BaseResponse.error("非法设备", ResultCode.PARAM_ERROR);
        }
        PaasGatewayCredentials gatewayCredentials = gatewayService.getById(gatewayBindSubDeviceRequest.getGwId());
        List<DeviceBasicData> subDevices = rexolarApiClient.getToRelationsInfo(token, gatewayCredentials.getGwId(), "DEVICE");
        List<String> subDeviceName = subDevices.stream().map(DeviceBasicData::getName).collect(Collectors.toList());
        if (!subDeviceName.contains(gatewayBindSubDeviceRequest.getDeviceName())){
            log.error("bindSubDevice deviceName is not exist, gatewayBindSubDeviceRequest:{}", gatewayBindSubDeviceRequest);
            return BaseResponse.error("设备尚未入网", ResultCode.PARAM_ERROR);
        }

        return BaseResponse.ok(gatewayService.bindSubDevice(gatewayBindSubDeviceRequest.getGwId(), device, token));
    }

    @PostMapping("/unbindSubDevice")
    @ResponseBody
    public BaseResponse unbindSubDevice(HttpServletRequest request, @RequestBody GatewayUnBindSubDeviceRequest gatewayUnBindSubDeviceRequest) {
        log.info("bindSubDevice, gatewayUnBindSubDeviceRequest:{}", gatewayUnBindSubDeviceRequest);
        if (StringUtils.isBlank(gatewayUnBindSubDeviceRequest.getDeviceName())){
            log.error("unbindSubDevice deviceName is null, gatewayBindSubDeviceRequest:{}", gatewayUnBindSubDeviceRequest);
            return BaseResponse.error("参数为空", ResultCode.PARAM_ERROR);
        }
        if (gatewayUnBindSubDeviceRequest.getGwId()==null){
            log.error("unbindSubDevice gwId is null, gatewayUnBindSubDeviceRequest:{}", gatewayUnBindSubDeviceRequest);
            return BaseResponse.error("参数为空", ResultCode.PARAM_ERROR);
        }
        String token = request.getHeader("token");
        Boolean flag =  checkGateway(gatewayUnBindSubDeviceRequest.getGwId(), token);
        if(!flag){
            log.error("unbindSubDevice checkGateway error, id:{}, token:{}", gatewayUnBindSubDeviceRequest.getGwId(), token);
            return BaseResponse.error("非法网关", ResultCode.PARAM_ERROR);
        }
        DeviceBasicData device = rexolarApiClient.getDeviceByDeviceName(gatewayUnBindSubDeviceRequest.getDeviceName(), token);
        if(device==null){
            log.error("unbindSubDevice getDeviceByDeviceName error, deviceName:{}", gatewayUnBindSubDeviceRequest.getDeviceName());
            return BaseResponse.error("设备不存在", ResultCode.PARAM_ERROR);
        }
        if (!device.getTenantId().equals(JwtUtils.getTenantId(token))){
            log.error("unbindSubDevice tenantId not match, tenantId:{}, device:{}", JwtUtils.getTenantId(token), device);
            return BaseResponse.error("非法设备", ResultCode.PARAM_ERROR);
        }
        PaasGatewayCredentials gatewayCredentials = gatewayService.getById(gatewayUnBindSubDeviceRequest.getGwId());
        return BaseResponse.ok(gatewayService.unbindSubDevice(gatewayCredentials.getGwId(), device.getCoreId(), gatewayUnBindSubDeviceRequest.getDeviceName(), token));
    }

    @PostMapping("/deleteSubDevice")
    @ResponseBody
    public BaseResponse deleteSubDevice(HttpServletRequest request, @RequestBody GatewayUnBindSubDeviceRequest gatewayUnBindSubDeviceRequest) {
        log.info("deleteSubDevice, gatewayUnBindSubDeviceRequest:{}", gatewayUnBindSubDeviceRequest);
        if (StringUtils.isBlank(gatewayUnBindSubDeviceRequest.getDeviceName())){
            log.error("deleteSubDevice deviceName is null, gatewayBindSubDeviceRequest:{}", gatewayUnBindSubDeviceRequest);
            return BaseResponse.error("参数为空", ResultCode.PARAM_ERROR);
        }
        if (gatewayUnBindSubDeviceRequest.getGwId()==null){
            log.error("deleteSubDevice gwId is null, gatewayUnBindSubDeviceRequest:{}", gatewayUnBindSubDeviceRequest);
            return BaseResponse.error("参数为空", ResultCode.PARAM_ERROR);
        }
        String token = request.getHeader("token");
        Boolean flag =  checkGateway(gatewayUnBindSubDeviceRequest.getGwId(), token);
        if(!flag){
            log.error("deleteSubDevice checkGateway error, id:{}, token:{}", gatewayUnBindSubDeviceRequest.getGwId(), token);
            return BaseResponse.error("非法网关", ResultCode.PARAM_ERROR);
        }
        DeviceBasicData device = rexolarApiClient.getDeviceByDeviceName(gatewayUnBindSubDeviceRequest.getDeviceName(), token);
        if(device==null){
            log.error("deleteSubDevice getDeviceByDeviceName error, deviceName:{}", gatewayUnBindSubDeviceRequest.getDeviceName());
            return BaseResponse.error("设备不存在", ResultCode.PARAM_ERROR);
        }
        if (!device.getTenantId().equals(JwtUtils.getTenantId(token))){
            log.error("deleteSubDevice tenantId not match, tenantId:{}, device:{}", JwtUtils.getTenantId(token), device);
            return BaseResponse.error("非法设备", ResultCode.PARAM_ERROR);
        }
        PaasGatewayCredentials gatewayCredentials = gatewayService.getById(gatewayUnBindSubDeviceRequest.getGwId());
        return BaseResponse.ok(gatewayService.deleteSubDevice(gatewayCredentials.getGwId(), device.getCoreId(), gatewayUnBindSubDeviceRequest.getDeviceName(), token));
    }

    @GetMapping("/join/list")
    public BaseResponse joinList(HttpServletRequest request, @RequestParam Long id) {
        log.info("joinList, id:{}", id);
        String token = request.getHeader("token");
        String tenantId = JwtUtils.getTenantId(token);
        Boolean flag =  checkGateway(id, tenantId);
        if(!flag){
            log.error("joinList checkGateway error, id:{}, token:{}", id, token);
            return BaseResponse.error("非法网关", ResultCode.PARAM_ERROR);
        }
        return BaseResponse.ok(gatewayService.joinList(id));
    }

    @PostMapping("/addSubDevice")
    @ResponseBody
    public BaseResponse addSubDevice(HttpServletRequest request, @RequestBody GatewayAddSubDeviceRequest gatewayAddSubDeviceRequest) {
        log.info("addSubDevice, gatewayAddSubDeviceRequest:{}", gatewayAddSubDeviceRequest);
        if(StringUtils.isBlank(gatewayAddSubDeviceRequest.getDeviceName())){
            log.error("addSubDevice deviceName is null, gatewayAddSubDeviceRequest:{}", gatewayAddSubDeviceRequest);
            return BaseResponse.error("参数为空", ResultCode.PARAM_ERROR);
        }
        if(StringUtils.isBlank(gatewayAddSubDeviceRequest.getCategoryId())){
            log.error("addSubDevice categoryId is null, gatewayAddSubDeviceRequest:{}", gatewayAddSubDeviceRequest);
            return BaseResponse.error("参数为空", ResultCode.PARAM_ERROR);
        }
        String token = request.getHeader("token");
        String tenantId = JwtUtils.getTenantId(token);
        Boolean flag =  checkGateway(gatewayAddSubDeviceRequest.getGwId(), tenantId);
        if(!flag){
            log.error("addSubDevice checkGateway error, id:{}, token:{}", gatewayAddSubDeviceRequest.getGwId(), token);
            return BaseResponse.error("非法网关", ResultCode.PARAM_ERROR);
        }
        String deviceName = null;
        if(gatewayAddSubDeviceRequest.getDeviceName().contains("_")){
            deviceName = gatewayAddSubDeviceRequest.getDeviceName().substring(0, gatewayAddSubDeviceRequest.getDeviceName().indexOf("_"));
        }else {
            deviceName = gatewayAddSubDeviceRequest.getDeviceName();
        }
        DeviceBasicData device = rexolarApiClient.getDeviceByDeviceName(deviceName, token);
        if(device==null){
            log.error("addSubDevice device is null, deviceName:{}", gatewayAddSubDeviceRequest.getDeviceName());
            return BaseResponse.error("设备不存在", ResultCode.PARAM_ERROR);
        }
        if(!device.getTenantId().equals(JwtUtils.getTenantId(token))){
            log.error("addSubDevice device tenantId not match, tenantId:{}, device:{}", JwtUtils.getTenantId(token), device);
            return BaseResponse.error("非法设备", ResultCode.PARAM_ERROR);
        }
        return BaseResponse.ok(gatewayService.addSubDevice(gatewayAddSubDeviceRequest.getGwId(), device, token));
    }

}
